<script setup lang="ts">
import router from '@/router'
import {
  addPatient,
  delPatient,
  editPatient,
  getPatientList
} from '@/services/user'
import { useConsultStore } from '@/stores'
import type {
  Patient,
  PatientList,
  PatientOfAddFormData,
  PatientOfEditFormData
} from '@/types/user'
import _ from 'lodash'
import { showConfirmDialog, showSuccessToast, type FormInstance } from 'vant'
import { computed, onMounted, ref, watch } from 'vue'
import { useRoute } from 'vue-router'

const route = useRoute()

const isChange = computed(() => {
  return route.query.isChange === '1' ? true : false
})

const consultStore = useConsultStore()

const list = ref<PatientList>([])

const loadList = async () => {
  list.value = await getPatientList()
}

onMounted(async () => {
  await loadList()
  // 只有当从问诊记录过来时，才需要选中患者
  if (isChange.value && consultStore.consult.patientId === undefined) {
    consultStore.setPatientId(list.value[0]?.id)
  }
})

// #region 添加患者相关代码块
const showPopupOfAdd = ref(false)

// 获取添加表单的初始值
const getInitFormDataOfAdd = (): PatientOfAddFormData => ({
  name: '',
  idCard: '',
  defaultFlag: 0,
  gender: 1
})

const formDataOfAdd = ref<PatientOfAddFormData>(getInitFormDataOfAdd())

const refFormOfAdd = ref<FormInstance>()

const save = async () => {
  // 在发出请求之前，将布尔值转换成数字
  // formDataOfAdd.value.defaultFlag = +formDataOfAdd.value.defaultFlag as 0 | 1
  await refFormOfAdd.value?.validate()
  // 能够走下来，说明整个表单校验通过
  await addPatient(formDataOfAdd.value)
  // 添加成功后，要提示，要关闭弹窗，重置表单，要刷新列表
  showSuccessToast('添加成功')
  showPopupOfAdd.value = false
  // 在做重置时，表单数据中的 gender 可能会发生了变化，一旦发生变化，就会触发侦听器，侦听中会校验身份证号
  formDataOfAdd.value = getInitFormDataOfAdd()
  await loadList()
}
// 当性别发生变化时，验证身份证号
watch(
  () => formDataOfAdd.value.gender,
  async () => {
    // 如果弹层是打开的，才需要校验
    if (showPopupOfAdd.value) {
      refFormOfAdd.value?.validate('idCard')
    }
  }
)

const openPopupOfAdd = () => {
  // 由于，有可能，用户还没有输入完，没点击保存按钮，如果关闭了再次打开，数据就没了，可能影响用户心情
  // formDataOfAdd.value = getInitFormDataOfAdd()
  showPopupOfAdd.value = true
}

// #endregion

// #region 编辑患者相关代码块
const showPopupOfEdit = ref(false)

// 获取添加表单的初始值
const getInitFormDataOfEdit = (): PatientOfEditFormData => ({
  id: '',
  name: '',
  idCard: '',
  defaultFlag: 0,
  gender: 1
})

const formDataOfEdit = ref<PatientOfEditFormData>(getInitFormDataOfEdit())

const refFormOfEdit = ref<FormInstance>()

const edit = async () => {
  // 在发出请求之前，将布尔值转换成数字
  // formDataOfEdit.value.defaultFlag = +formDataOfEdit.value.defaultFlag as 0 | 1
  await refFormOfEdit.value?.validate()
  // 能够走下来，说明整个表单校验通过
  await editPatient(formDataOfEdit.value)
  // 编辑成功后，要提示，要关闭弹窗，重置表单，要刷新列表
  showSuccessToast('编辑成功')
  showPopupOfEdit.value = false
  // 编辑时，不需要重置数据，因为弹出时会回显初始数据
  // formDataOfEdit.value = getInitFormDataOfEdit()
  await loadList()
}
// 当性别发生变化时，验证身份证号
watch(
  () => formDataOfEdit.value.gender,
  () => {
    refFormOfEdit.value?.validate('idCard')
  }
)

const openPopupOfEdit = (p: Patient) => {
  formDataOfEdit.value = _.pick(p, [
    'id',
    'name',
    'idCard',
    'defaultFlag',
    'gender'
  ])

  // 由于，有可能，用户还没有输入完，没点击保存按钮，如果关闭了再次打开，数据就没了，可能影响用户心情
  // formDataOfEdit.value = getInitFormDataOfEdit()
  showPopupOfEdit.value = true
}

// #endregion

// #region 删除患者
const del = async () => {
  await showConfirmDialog({
    title: '温馨提示',
    message: `你确定要删除 ${formDataOfEdit.value.name} 患者信息吗？`
  })

  await delPatient(formDataOfEdit.value.id)

  showSuccessToast('删除成功')

  // 如果 是从问诊记录过来的 并且 此时删除的是 选中的患者，那么需要将选中的患者重置为第一个
  if (
    isChange.value &&
    formDataOfEdit.value.id === consultStore.consult.patientId
  ) {
    consultStore.setPatientId(list.value[0]?.id)
  }

  showPopupOfEdit.value = false

  await loadList()
}
// #endregion
</script>

<template>
  <div class="patient-page">
    <cp-nav-bar :title="isChange ? '选择患者' : '家庭档案'"></cp-nav-bar>

    <!-- 头部提示 -->
    <div v-if="isChange" class="patient-change">
      <h3>请选择患者信息</h3>
      <p>以便医生给出更准确的治疗，信息仅医生可见</p>
    </div>

    <div class="patient-list">
      <div
        v-for="v of list"
        :key="v.id"
        class="patient-item"
        :class="{
          selected: isChange && consultStore.consult.patientId === v.id
        }"
        @click="isChange && consultStore.setPatientId(v.id)"
      >
        <div class="info">
          <span class="name">{{ v.name }}</span>
          <span class="id">{{
            v.idCard.replace(/(.{6}).+(.{4})/, '$1********$2')
          }}</span>
          <span>{{ v.genderValue }}</span>
          <span>{{ v.age }}岁</span>
        </div>
        <div class="icon" @click="openPopupOfEdit(v)">
          <cp-icon name="user-edit" />
        </div>
        <div v-if="v.defaultFlag === 1" class="tag">默认</div>
      </div>
      <div class="patient-add" @click="openPopupOfAdd">
        <cp-icon name="user-add" />
        <p>添加患者</p>
      </div>
      <div class="patient-tip">最多可添加 6 人</div>
    </div>

    <!-- 底部按钮 -->
    <div class="patient-next" v-if="isChange">
      <van-button
        type="primary"
        round
        block
        @click="router.push({ name: 'ConsultPay' })"
      >
        下一步
      </van-button>
    </div>
  </div>

  <!-- 添加患者弹层 -->
  <van-popup
    v-model:show="showPopupOfAdd"
    :style="{ width: '100%', height: '100%' }"
    position="right"
  >
    <cp-nav-bar
      title="添加患者"
      right-text="保存"
      @click-right="save"
      :click-left="() => (showPopupOfAdd = false)"
    />

    <!-- 直接写 style 的话，postcss-px-to-viewport 插件就不会处理 -->
    <div class="pt46"></div>

    <!-- 保存按钮在 cp-nav-bar 组件内部，不在 van-form 下，所以触发不了 submit 事件，只能在点击保存时手动校验整个表单 -->
    <van-form autocomplete="off" ref="refFormOfAdd">
      <van-field
        label="真实姓名"
        placeholder="请输入真实姓名"
        v-model="formDataOfAdd.name"
        :rules="[
          { required: true, message: '请输入姓名' },
          {
            pattern: /^(?:[\u4e00-\u9fa5·]{2,16})$/,
            message: '中文2-16个字符'
          }
        ]"
      />
      <van-field
        label="身份证号"
        name="idCard"
        placeholder="请输入身份证号"
        v-model="formDataOfAdd.idCard"
        :rules="[
          { required: true, message: '请输入身份证号' },
          {
            pattern:
              /^[1-9]\d{5}(?:18|19|20)\d{2}(?:0[1-9]|10|11|12)(?:0[1-9]|[1-2]\d|30|31)\d{3}[\dXx]$/,
            message: '身份证号不正确'
          },
          {
            validator(value: string) {
              // sexNumber：取身份证倒数第2位，除以2取余，余数为 1 是男，为 0 是女
              const sexNumber = +value.slice(-2, -1) % 2
              if (sexNumber !== formDataOfAdd.value.gender) {
                // 验证不通过，返回错误消息
                return '性别和身份证号上的不符'
              }
              // 验证通过
              return true
            }
          }
        ]"
      />
      <van-field label="性别" class="pb4">
        <!-- 单选按钮组件 -->
        <template #input>
          <cp-radio-btn
            v-model="formDataOfAdd.gender"
            :options="[
              { label: '男', value: 1 },
              { label: '女', value: 0 }
            ]"
          ></cp-radio-btn>
        </template>
      </van-field>
      <van-field label="默认就诊人">
        <template #input>
          <!-- <van-checkbox v-model="formDataOfAdd.defaultFlag" :icon-size="18" round /> -->
          <!-- 这个 van-checkbox 组件不支持通过属性自定义选中和未选中的值，需要自己处理一下 -->
          <van-checkbox
            :model-value="formDataOfAdd.defaultFlag === 1"
            @update:model-value="formDataOfAdd.defaultFlag = $event ? 1 : 0"
            :icon-size="18"
            round
          />
        </template>
      </van-field>
    </van-form>
  </van-popup>

  <!-- 编辑患者弹层 -->
  <van-popup
    v-model:show="showPopupOfEdit"
    :style="{ width: '100%', height: '100%' }"
    position="right"
  >
    <cp-nav-bar
      title="编辑患者"
      right-text="保存"
      @click-right="edit"
      :click-left="() => (showPopupOfEdit = false)"
    />

    <!-- 直接写 style 的话，postcss-px-to-viewport 插件就不会处理 -->
    <div class="pt46"></div>

    <!-- 保存按钮在 cp-nav-bar 组件内部，不在 van-form 下，所以触发不了 submit 事件，只能在点击保存时手动校验整个表单 -->
    <van-form autocomplete="off" ref="refFormOfEdit">
      <van-field
        label="真实姓名"
        placeholder="请输入真实姓名"
        v-model="formDataOfEdit.name"
        :rules="[
          { required: true, message: '请输入姓名' },
          {
            pattern: /^(?:[\u4e00-\u9fa5·]{2,16})$/,
            message: '中文2-16个字符'
          }
        ]"
      />
      <van-field
        label="身份证号"
        name="idCard"
        placeholder="请输入身份证号"
        v-model="formDataOfEdit.idCard"
        :rules="[
          { required: true, message: '请输入身份证号' },
          {
            pattern:
              /^[1-9]\d{5}(?:18|19|20)\d{2}(?:0[1-9]|10|11|12)(?:0[1-9]|[1-2]\d|30|31)\d{3}[\dXx]$/,
            message: '身份证号不正确'
          },
          {
            validator(value: string) {
              // sexNumber：取身份证倒数第2位，除以2取余，余数为 1 是男，为 0 是女
              const sexNumber = +value.slice(-2, -1) % 2
              if (sexNumber !== formDataOfEdit.value.gender) {
                // 验证不通过，返回错误消息
                return '性别和身份证号上的不符'
              }
              // 验证通过
              return true
            }
          }
        ]"
      />
      <van-field label="性别" class="pb4">
        <!-- 单选按钮组件 -->
        <template #input>
          <cp-radio-btn
            v-model="formDataOfEdit.gender"
            :options="[
              { label: '男', value: 1 },
              { label: '女', value: 0 }
            ]"
          ></cp-radio-btn>
        </template>
      </van-field>
      <van-field label="默认就诊人">
        <template #input>
          <!-- <van-checkbox v-model="formDataOfEdit.defaultFlag" :icon-size="18" round /> -->
          <!-- 这个 van-checkbox 组件不支持通过属性自定义选中和未选中的值，需要自己处理一下 -->
          <van-checkbox
            :model-value="formDataOfEdit.defaultFlag === 1 ? true : false"
            @update:model-value="formDataOfEdit.defaultFlag = $event ? 1 : 0"
            :icon-size="18"
            round
          />
        </template>
      </van-field>
    </van-form>

    <van-action-bar>
      <van-action-bar-button @click="del">删除</van-action-bar-button>
    </van-action-bar>
  </van-popup>
</template>

<style lang="scss" scoped>
.patient-change {
  padding: 15px;
  > h3 {
    font-weight: normal;
    margin-bottom: 5px;
  }
  > p {
    color: var(--cp-text3);
  }
}
.patient-next {
  padding: 15px;
  background-color: #fff;
  position: fixed;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 80px;
  box-sizing: border-box;
}

// 底部操作栏
.van-action-bar {
  padding: 0 10px;
  margin-bottom: 10px;
  .van-button {
    color: var(--cp-price);
    background-color: var(--cp-bg);
  }
}
.pt46 {
  padding-top: 46px;
}
.patient-page {
  padding: 46px 0 80px;
}
.patient-list {
  padding: 15px;
}
.patient-item {
  display: flex;
  align-items: center;
  padding: 15px;
  background-color: var(--cp-bg);
  border-radius: 8px;
  margin-bottom: 15px;
  position: relative;
  border: 1px solid var(--cp-bg);
  transition: all 0.3s;
  overflow: hidden;
  .info {
    display: flex;
    flex-wrap: wrap;
    flex: 1;
    span {
      color: var(--cp-tip);
      margin-right: 20px;
      line-height: 30px;
      &.name {
        font-size: 16px;
        color: var(--cp-text1);
        width: 80px;
        margin-right: 0;
      }
      &.id {
        color: var(--cp-text2);
        width: 180px;
      }
    }
  }
  .icon {
    color: var(--cp-tag);
    width: 20px;
    text-align: center;
  }
  .tag {
    position: absolute;
    right: 60px;
    top: 21px;
    width: 30px;
    height: 16px;
    font-size: 10px;
    color: #fff;
    background-color: var(--cp-primary);
    border-radius: 2px;
    display: flex;
    justify-content: center;
    align-items: center;
  }
  &.selected {
    border-color: var(--cp-primary);
    background-color: var(--cp-plain);
    .icon {
      color: var(--cp-primary);
    }
  }
}
.patient-add {
  background-color: var(--cp-bg);
  color: var(--cp-primary);
  text-align: center;
  padding: 15px 0;
  border-radius: 8px;
  .cp-icon {
    font-size: 24px;
  }
}
.patient-tip {
  color: var(--cp-tag);
  padding: 12px 0;
}
.pb4 {
  padding-bottom: 4px;
}
</style>
